//==============================================================================
//
//             DSemaphore - the semaphore class in the ofc-library
//
//               Copyright (C) 2011  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2008-07-20 14:03:51 $ $Revision: 1.11 $
//
//==============================================================================

#include "ofc/DSemaphore.h"


#if _INTERFACE_

#include "ofc/config.h"

#if defined(HAVE_LIBPTHREAD)
#define HAVE_DSEMAPHORE
#endif

#ifdef HAVE_DSEMAPHORE
//
// The Semaphore class implements methods for using a semaphore. It uses the
// Objective-Cs mutex functions for protecting the semaphore.
//
// @example
// XXX
// 

@interface DSemaphore : DObject
{
@private
  objc_mutex_t  _mutex;    // the mutex for the value
  objc_mutex_t  _wait;     // the mutex for waiting
  int           _value;    // the semaphore value
}
#endif
#endif


#ifdef HAVE_DSEMAPHORE


@implementation DSemaphore


//// Constructors

//
// Initialise a semaphore with value 0
//
// @return the object
//

- (DSemaphore *) init
{
  [self init :0];

  return self;
}

//
// Initialise a semaphore with a initial value
// 
// @param value    the initial value (>=0)
// 
// @return the object
// 

- (DSemaphore *) init :(int) value
{
  [super init];
  
  _value    = (value < 0 ? 0 : value);
  _mutex    = objc_mutex_allocate();
  _wait     = objc_mutex_allocate();
  
  return self;
}


//// Copy related methods

//
// Do a shallow copy of the object (not implemented)
//
// @return the object
//
- shallowCopy
{
  WARNING(DW_METHOD_NOT_IMPL, "shallowCopy");
  
  return [super shallowCopy];
}


//// Deconstructor

//
// Free the object
// 

- free
{
  objc_mutex_deallocate(_mutex);
  objc_mutex_deallocate(_wait);

  [super free];
  
  return self;
}


//// Main methods

//
// Signal the semaphore by incrementing the value
//
// @return success
//

- (id) signal
{
  objc_mutex_lock(_mutex);

  _value++;
  if (_value <= 0)
  {
    objc_mutex_unlock(_wait);
  }
  else
  {
    objc_mutex_unlock(_mutex);
  }

  return self;
}

//
// If the semaphore value is zero (or lower) wait else decrement the value.
//
// @return the object
//

- (id) wait
{
  objc_mutex_lock(_mutex);
  _value--;

  if (_value < 0)
  {
    objc_mutex_unlock(_mutex);
    objc_mutex_lock(_wait);
  }
  objc_mutex_unlock(_mutex);
}

//
// If the semaphores value is greater than zero, decrement the value, else do nothing
//
// @return is the semaphore decremented ?
//

- (BOOL) try
{
  BOOL ok = NO;

  objc_mutex_lock(_mutex);

  if (_value > 0)
  {
    _value--;

    ok = YES;
  }
  objc_mutex_unlock(_mutex);
}

@end
#endif

/*===========================================================================*/

